package com.wtwd.campus.attendancenetty;

import com.wtwd.campus.attendancereceiver.AttendanceReceiver;
import com.wtwd.campus.attendancereceiver.AttendanceReceiverFactory;
import com.wtwd.campus.common.Constants;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;

/**
 * 处理连接与通讯
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {
    private final static Logger logger = LoggerFactory.getLogger(ServerHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
        String clientIp = insocket.getAddress().getHostAddress();
        System.out.println("收到客户端[ip:" + clientIp + "]连接");
    }


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // TODO 这里的msg是在解码器里面 out.add(Object msg)里的内容。按照解码器来说，就是 5AxxxxxxxxxxCA
        // TODO 按照以上消息解析，可以构建对应工厂，拆分到每个类。
        // TODO 如果收到了考勤信息上来了（A7）。里面有一个serialNo。根据productNo和这个serialNo设置一个一分钟过期的redisKeys(在A7的具体解析中实现)
        // TODO 如果在一分钟内同一个productNo的A7指令的serialNo重复了，则不进行数据处理，但是还是需要应答
        // 1.msg转为实际操作实体类  2.保存通道或者刷新通道  3.处理消息  4.写入ctx作为回复   5.写入异常则关闭通道；成功则保存通道
        AttendanceReceiver receiver = AttendanceReceiverFactory.createReceiver(String.valueOf(msg));
        logger.info("解析到指令：" + msg.toString());
        if (receiver != null) {
            //解析数据，并把数据往后端传
            try {
                //先进行指令的解析,得到设备终端号
                String productNo = receiver.parseMessage(String.valueOf(msg),ctx.channel());
                if(StringUtils.isBlank(productNo)){
                    //指令有误或者是A7指令，直接返回
                    return;
                }
                //保存或者刷新通道
                AttendanceChannelHandler.addOrRefreshChannel(productNo, ctx.channel());
            } catch (Exception e) {
                logger.error("数据解析异常[{}]", e.getMessage());
            } finally {
                ReferenceCountUtil.release(msg);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        AttendanceChannelHandler.closeChannel(ctx.channel());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        logger.info("主动断开连接，通道关闭");
        AttendanceChannelHandler.closeChannel(ctx.channel());
    }

}